/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.web.service.support.storage.mgt;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.vacoor.nothing.common.util.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * FTP 存储实现
 *
 * @author vacoor
 */
public class FtpStorageManagerImpl extends GeneralStorageManager {
    private static final Logger LOG = LoggerFactory.getLogger(FtpStorageManagerImpl.class);

//    private static final String TEMP_FILE_PREFIX = FtpStorageImpl.class.getName() + '-';
//    private static final String TEMP_FILE_SUFFIX = ".tmp";

    public static final int DEFAULT_PORT = 21;
    public static final String DEFAULT_ENCODING = "UTF-8";

    private final ThreadLocal<FTPClient> client = new ThreadLocal<FTPClient>();

    private String host;
    private int port = DEFAULT_PORT;
    private String username;
    private String password;
    private String encoding = DEFAULT_ENCODING;

    @Override
    public boolean exists(String remotePath) {
        remotePath = normalizePath(remotePath);

        try {
            FTPClient ftp = getFtpClient();
            FTPFile[] files = ftp.listFiles(remotePath);
            return 0 < files.length;
        } catch (IOException e) { /* ignore */ }
        return false;
    }

    @Override
    public boolean readTo(String remotePath, OutputStream out, boolean closeOut) throws IOException {
        boolean success = false;
        remotePath = normalizePath(remotePath);

        try {
            FTPClient ftp = getFtpClient();
            success = ftp.retrieveFile(remotePath, out);
        } finally {
            if (closeOut) {
                IOUtils.close(out);
            }
        }
        return success;
    }

    @Override
    public void store(InputStream is, String remotePath) throws IOException {
        remotePath = normalizePath(remotePath);
        int i = remotePath.lastIndexOf("/");

        FTPClient ftp = getFtpClient();
        mkdirs(ftp, 0 < i ? remotePath.substring(0, i) : remotePath);
        ftp.appendFile(remotePath, is);
    }

    @Override
    public void mkdirs(String path) {

    }

    @Override
    public void close() {
        disconnect();
    }


    // delete
    // read


    /* ****************************************
     *   FtpClient Helper Method
     * *****************************************/

    protected boolean mkdirs(FTPClient ftp, String remotePath) throws IOException {
        if (null != ftp && !StringUtils.isEmpty(remotePath) && ftp.isConnected()) {
            // TODO
//            ftp.makeDirectory(remote); can not cascade
        }
        return false;
    }

    /**
     * 获取当前线程上下文中可用的 FTP Client
     *
     * @return
     * @throws IOException
     */

    protected FTPClient getFtpClient() throws IOException {
        FTPClient ftp = client.get();
        if (null != ftp && ftp.isConnected()) {
            return ftp;
        }
        ftp = new FTPClient();
        try {
            ftp.connect(getHost(), getPort());
            ftp.enterLocalPassiveMode();

            if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
                throw new RuntimeException("FTP server refused connection.");
            }

            // ftp.setAutodetectUTF8(true);
            ftp.setControlEncoding(getEncoding());
            ftp.setFileTransferMode(FTP.BINARY_FILE_TYPE);
            // ftp.setSoTimeout();
            // ftp.setDataTimeout();
            // ftp.setConnectTimeout();

            if (!ftp.login(getUsername(), getPassword())) {
                client.set(null);
                throw new RuntimeException("FTP server login failure");
            }

            client.set(ftp);
            return ftp;
        } catch (IOException e) {
            disconnect();
            throw e;
        }
    }

    protected void disconnect() {
        FTPClient ftp = client.get();
        if (null != ftp && ftp.isConnected()) {
            try {
                ftp.logout();
                ftp.disconnect();
            } catch (IOException ignore) {
                // ignore
            } finally {
                client.set(null);
            }
        }
    }

    /* **************************
     *     GETTER / SETTER
     * **************************/

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }
}
